﻿using System.Reflection;
using System.Runtime.Loader;

public class PluginLoadContext : AssemblyLoadContext
{
    private readonly AssemblyDependencyResolver _resolver;

    public PluginLoadContext(string pluginPath) : base(isCollectible: true)
    {
        _resolver = new AssemblyDependencyResolver(pluginPath);
    }

    protected override Assembly? Load(AssemblyName assemblyName)
    {
        // 尝试从默认上下文加载共享程序集（如系统程序集）
        if (IsSharedAssembly(assemblyName.Name!))
        {
            return AssemblyLoadContext.Default.LoadFromAssemblyName(assemblyName);
        }

        // 使用依赖解析器定位程序集
        string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
        return assemblyPath != null ? LoadFromAssemblyPath(assemblyPath) : null;
    }

    protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
    {
        string? libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
        return libraryPath != null ? LoadUnmanagedDllFromPath(libraryPath) : IntPtr.Zero;
    }

    private static bool IsSharedAssembly(string assemblyName)
    {
        return assemblyName.StartsWith("System.") ||
               assemblyName.StartsWith("Microsoft.") ||
               assemblyName == "netstandard" ||
               assemblyName == "mscorlib";
    }
}

public class PluginLoader
{
    public PluginLoadContext? Context { get; private set; }
    public Assembly? LoadedAssembly { get; private set; }

    public Assembly LoadPlugin(string pluginPath)
    {
        // 创建新的隔离加载上下文
        Context = new PluginLoadContext(pluginPath);

        // 从文件加载程序集
        using var stream = new FileStream(pluginPath, FileMode.Open, FileAccess.Read);
        LoadedAssembly = Context.LoadFromStream(stream);

        Console.WriteLine($"Loaded plugin: {Path.GetFileName(pluginPath)}");
        return LoadedAssembly;
    }

    public void UnloadPlugin()
    {
        if (Context == null) return;

        // 触发卸载
        Context.Unload();
        Context = null;
        LoadedAssembly = null;

        // 帮助GC回收资源
        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine("Plugin unloaded");
    }
}